/*
 * player_data.h
 *
 *  Created on: Aug 14, 2013
 *      Author: killerg
 */

#ifndef PLAYER_DATA_H_
#define PLAYER_DATA_H_


#include "share/cs_msg.pb.h"
#include "share/bitset.h"
#include "share/json/json-forwards.h"
#include "share/db_mgr.h"

using cs::EPlAtt8Save;
using cs::EPlAtt4Save;
using cs::EPlAttDSave;
using cs::EPlAttSSave;

using cs::EPeAtt8Save;
using cs::EPeAtt4Save;
using cs::EPeAttDSave;
using cs::EPeAttSSave;


#include "attribute.h"
#include "sync_att.h"
#include "proto_mgr.h"

struct client_session_t;
struct unit_t;

struct sprite_t {
    const tagProtoSprite* proto;
    int32_t serial;

    int32_t skill_level[SpriteSkillNum];
    bool init(sprite_t* sprite);
    bool init(int32_t protoid, int32_t serial);
    bool init(const Json::Value &json);
    bool save(Json::Value &json);
    void destroy();
    int32_t calc_combat_force();
};

struct pet_t {
    const tagProtoPet* proto;
    int32_t serial;
    const int32_t* def_att;
    unit_t* unit;
    enum EType {
    	ET_Normal = 0,
    	ET_WorldBoss = 1,
    } type = ET_Normal;

    pet_t() {
        proto = NULL;
        serial = -1;
        def_att = NULL;
        unit = NULL;
    }

    bool init(pet_t* pet);
    bool init(int32_t protoid, int32_t serial, int32_t level = 1);
    bool init(int32_t protoid, int32_t serial, const int32_t* def_att, int32_t level, const int32_t skill[PetSpecSkillNum]);
    bool init(const Json::Value &json);
    bool save(Json::Value &json);
    void destroy();

    void fill_opet(cs::OPet* pet);
    bool need_sync_pet();
    void fill_opetsync(cs::OPetSync* petsync);

    bool calc_att(bool level_pet = false);
    int32_t calc_star_level();


    sync_att_t<EPeAtt8Save> s8;
    sync_att_t<EPeAtt4Save> s4;
    sync_att_t<EPeAttDSave> sd;
    sync_att_t<EPeAttSSave> ss;

    int64_t att(EPeAtt8Save att) { return s8.get(att); }
    int32_t att(EPeAtt4Save att) { return s4.get(att); }
    double_t att(EPeAttDSave att) { return sd.get(att); }
    string att(EPeAttSSave att) { return ss.get(att); }

    void att(EPeAtt8Save att, int64_t value, bool force_sync = false);
    void att(EPeAtt4Save att, int32_t value, bool force_sync = false);
    void att(EPeAttDSave att, double_t value, bool force_sync = false);
    void att(EPeAttSSave att, const string &value, bool force_sync = false);

    void on_attchg(EPeAtt8Save att, int64_t value, bool init = false);
    void on_attchg(EPeAtt4Save att, int32_t value, bool init = false);
    void on_attchg(EPeAttDSave att, double_t value, bool init = false);
    void on_attchg(EPeAttSSave att, const string &value, bool init = false);

    void _sync_reset();
    bool _need_sync_syncatt();
    bool _init_syncatt(int32_t protoid, int32_t level, const int32_t* def_att, const int32_t* spec_skill);
    bool _init_syncatt(const Json::Value &json);
    void _save_syncatt(Json::Value &json);
    void _fill_syncatt_init(cs::OPet* opet);
    void _fill_syncatt_sync(cs::OPetSync* spetsync);

    void add_exp(int32_t toadd);
    void calc_combat_force();
};



struct unit_t {
    unit_t():cur_sprite(-1) {
        memset(combat, -1, sizeof(combat));
    }
    ptr_map<int32_t, sprite_t*> sprites;
    int32_t cur_sprite;

    ptr_map<int32_t, pet_t*> pets;
    int32_t combat[PlayerCombatCSlotNum];

    virtual void destroy();
    virtual ~unit_t(){}
};

struct item_t {
    int32_t serial;
    const tagProtoItem* proto;
    int32_t num;

    bool init(int32_t serial, int32_t protoid, int32_t num);
    bool init(const Json::Value &json);
    void save(Json::Value &json);
};

struct equip_t {
    int32_t equip_level;
    int32_t enhance_num;
    int32_t star_num[CanSeePetAttNum];
    bool chg;

    equip_t();
};

struct player_t : unit_t, enable_shared_from_this<player_t> {

    struct save_t {
        int32_t valid_pet_serial;
        int32_t valid_item_serial;
        int32_t valid_sprite_serial;
        int32_t code;
        int32_t code_trytime;
        time_t logoff_date;
        time_t week_refresh_time;
        int32_t compensate_gain_stamp;
        int8_t forbid;	// forbid broad speek
    } n, p;


    int64_t id;
    client_session_t* sess;
    string account;
    time_t create;
    time_t image_stamp;

    player_t(){
        n.valid_pet_serial = 0;
        n.valid_item_serial = 0;
        n.valid_sprite_serial = 0;
        n.logoff_date = 1393862400;
        n.code = 0;
        n.code_trytime = 0;
        n.week_refresh_time = 0;
        n.compensate_gain_stamp = -1;
        n.forbid = 0;
        image_stamp = 0;

        id = -1;
        sess = NULL;
        fri_index = -1;
        alivecnt_chg = false;
        need_calc_total_cf = false;
        need_calc_cf = false;
        queuing = false;
        saving_count = 0;

        sav_stamp = -1;		// 保存的时间戳
        chg_stamp = -1;
        valid_worldchat = -1;
    }
    ~player_t() {
        destroy();
    }

    bool init_image(const Json::Value &json);
    bool init(const int64_t playerid, const string &name, const EPlayerSex &sex, const string &account);
    bool init(const Json::Value &json);
    void save(Json::Value &json);
    void update();

    bool add_sprite(sprite_t* added, bool init = false);
    sprite_t* remove_sprite(int32_t serial);
    void _fill_sprite_init(cs::OPlayer* player);
    bool _need_sync_sprite();
    void _fill_sprite_sync(cs::SPlayerSync* playersync);
    set<int32_t> sprite_chg;
    set<int32_t> sprite_remove;


    bool add_pet(pet_t* pet, bool init = false);
    pet_t* remove_pet(int32_t serial);
    pet_t* find_pet(int32_t serial);
    void _fill_pet_init(cs::OPlayer* player);
    bool _need_sync_pet();
    void _fill_pet_sync(cs::SPlayerSync* playersync);
    set<int32_t> pet_add;
    set<int32_t> pet_remove;

    void fill_oplayer(cs::OPlayer* player);
    bool need_sync_player();
    void fill_splayersync(cs::SPlayerSync* splayersync);
    void reset_sync();

    // bag ------------------------------------------------------------------------
    ptr_map<int32_t, item_t*> bag;    // serial, item
    set<int32_t> bag_mod; // serial

    item_t* get_bag_item(int32_t serial);
    int32_t get_bag_item_protoid_by_type(EItemType type);

    void clear_bag();
    bool can_add_item(int32_t protoid, int32_t num);
    void add_item(int32_t protoid, int32_t num);
    int32_t bag_free_slot();

    bool can_del_item(int32_t protoid, int32_t num);
    void del_item(int32_t protoid, int32_t num);

    bool can_del_item_by_serial(int32_t serial, int32_t num);
    void del_item_by_serial(int32_t serial, int32_t num);

    bool _need_sync_obag();
    void _fill_obag_init(cs::OPlayer* player);
    void _fill_obag_sync(cs::SPlayerSync* playersync);

    void _init_bag(const Json::Value &json);
    void _save_bag(Json::Value &json);
    void _destroy_bag();

    // equip ------------------------------------------------------------------------
    equip_t equip_bar[PlayerEquipSlotNum];

    void calc_equip_mod();

    bool _need_sync_equip_bar();
    void _init_equip_bar(const Json::Value &json);
    void _save_equip_bar(Json::Value &json);

    void _fill_equip_bar_init(cs::OPlayer* player);
    void _fill_equip_bar_sync(cs::SPlayerSync* playersync);

    // syncatt ------------------------------------------------------------------------
    sync_att_t<EPlAtt8Save> s8;
    sync_att_t<EPlAtt4Save> s4;
    sync_att_t<EPlAttDSave> sd;
    sync_att_t<EPlAttSSave> ss;
    sync_att_t<EPlAtt8Nosave> n8;
    sync_att_t<EPlAtt4Nosave> n4;

    int64_t att(EPlAtt8Save att) { return s8.get(att); }
    int32_t att(EPlAtt4Save att) { return s4.get(att); }
    double_t att(EPlAttDSave att) { return sd.get(att); }
    string att(EPlAttSSave att) { return ss.get(att); }
    int64_t att(EPlAtt8Nosave att) { return n8.get(att); }
    int32_t att(EPlAtt4Nosave att) { return n4.get(att); }

    void att(EPlAtt8Save att, int64_t value);
    void att(EPlAtt4Save att, int32_t value);
    void att(EPlAttDSave att, double_t value);
    void att(EPlAttSSave att, const string &value);
    void att(EPlAtt8Nosave att, int64_t value);
    void att(EPlAtt4Nosave att, int32_t value);

    void _on_attchg(EPlAtt8Save att, int64_t value, bool init = false);
    void _on_attchg(EPlAtt4Save att, int32_t value, bool init = false);
    void _on_attchg(EPlAttDSave att, double_t value, bool init = false);
    void _on_attchg(EPlAttSSave att, const string &value, bool init = false);
    void _on_attchg(EPlAtt8Nosave att, int64_t value);
    void _on_attchg(EPlAtt4Nosave att, int32_t value);

    bool _need_sync_nosaveatt() { return n8.chged.any() || n4.chged.any(); }
    bool _need_sync_syncatt();
    bool _init_syncatt();
    bool _init_syncatt(const Json::Value &json);
    void _save_syncatt(Json::Value &json);
    void _fill_syncatt_init(cs::OPlayer* oplayer);
    void _fill_syncatt_sync(cs::SPlayerSync* splayersync);
    void _on_att_chg();

    // boss 关卡 ---------------------------------------------------------------------
    struct boss_level_t {
        int32_t id;
        int32_t cur_pass;
        bool haspass;
        int32_t reset_count;
    };
    ptr_map<int32_t, boss_level_t*> _boss_level_progress;
    set<int32_t> _boss_level_chg;

    void _init_bosslevel(const Json::Value &json);
    void _save_bosslevel(Json::Value &json);
    void _destroy_bosslevel();
    void _fill_bosslevel_init(cs::OPlayer* oplayer);
    void _fill_bosslevel_sync(cs::SPlayerSync* splayersync);

    // 登录
    void on_logon(client_session_t* sess);
    // 登出
    void on_logoff();
    void _on_day_chg();
    void _on_week_chg();

    bool can_consume(int32_t consumeid);
    void consume(int32_t consumeid);

    void reward(int32_t rewardid, OReward* reward = NULL, double pct = 1.0f, int32_t reward_pet = -1);

    // 宠物图鉴 ---------------------------------------------------------------------
    unordered_set<int32_t> petseen;
    list<int32_t> petseen_added;

    void _init_petseen(const Json::Value &json);
    void _save_petseen(Json::Value &json);
    void _destroy_petseen();
    void _fill_petseen_init(cs::OPlayer* oplayer);
    void _fill_petseen_sync(cs::SPlayerSync* splayersync);

    unordered_set<int32_t> pethas;
    list<int32_t> pethas_added;

    void _init_pethas(const Json::Value &json);
    void _save_pethas(Json::Value &json);
    void _destroy_pethas();
    void _fill_pethas_init(cs::OPlayer* oplayer);
    void _fill_pethas_sync(cs::SPlayerSync* splayersync);

    // 探险图鉴 ---------------------------------------------------------------------
    my_bitset_t<MaxLevelNum> levelhas;
    list<int32_t> levelhas_added;

    void _init_levelhas(const Json::Value &json);
    void _save_levelhas(Json::Value &json);
    void _destroy_levelhas();
    void _fill_levelhas_init(cs::OPlayer* oplayer);
    void _fill_levelhas_sync(cs::SPlayerSync* splayersync);

    // 技能图鉴 ---------------------------------------------------------------------
    unordered_set<int32_t> skillhas;
    list<int32_t> skillhas_added;

    void _init_skillhas(const Json::Value &json);
    void _save_skillhas(Json::Value &json);
    void _destroy_skillhas();
    void _fill_skillhas_init(cs::OPlayer* oplayer);
    void _fill_skillhas_sync(cs::SPlayerSync* splayersync);


    // 战力 ------------------------------------------------------------------------
    void calc_combat_force();
    void calc_total_combat_force();
    bool need_calc_total_cf;
    bool need_calc_cf;


    // 好友 ------------------------------------------------------------------------
    set<int64_t> friends;
    set<int64_t> friends_chged;
    set<int64_t> friends_combated;
    set<int64_t> friends_combated_added;
    bool friends_combated_clear = false;
    int64_t fri_index;
    struct giftlog_t {
    	int32_t time;
    	string to;
    	string from;
    	cs::EFriendGiftType type;
    };
    list<giftlog_t> giftlog;
    list<giftlog_t> giftlog_added;
    void add_giftlog(int64_t sender, const string &to, const string &from, cs::EFriendGiftType type);

    void _init_friends(const Json::Value &json);
    void _save_friends(Json::Value &json);
    void _destroy_friends();
    void _fill_friends_init(cs::OPlayer* oplayer);
    void _fill_friends_sync(cs::SPlayerSync* splayersync);

    bool is_in_combat(int32_t pet_serial);

    // 竞技场日志------------------------------------------------------------------------
    struct arenalog_t {
        std::string attacker;
        std::string defender;
        bool win;
        int index;
    };
    list<arenalog_t> arenalog;
    void push_log(const arenalog_t &log) {
        arenalog.emplace_back(log);
        while (arenalog.size() > 3)
            arenalog.pop_front();
    }
    void _init_arenalogs(const Json::Value &json);
    void _save_arenalogs(Json::Value &json);
    void _destroy_arenalogs();

    // 存储 ------------------------------------------------------------------------
    time_t sav_stamp;		// 保存的时间戳
    time_t chg_stamp;
    bool queuing;
    int32_t saving_count;
    void post_save_db(function<void(db_error_t)> cb = NULL);
    bool add_save_queue(bool chg);
    // 活跃度 ------------------------------------------------------------------------
    set<int32_t> alives;
    bool alivecnt_chg;

    void _init_alives(const Json::Value &json);
    void _save_alives(Json::Value &json);
    void _destroy_alives();
    void _fill_alives_init(cs::OPlayer* oplayer);
    void _fill_alives_sync(cs::SPlayerSync* splayersync);

    time_t valid_worldchat;

    // train room ------------------------------------------------------------------------
    struct trainroom_t {
    	int32_t type = -1;	// -1 none 0 exp 1 money
    	int32_t lvl = 0;
    	int32_t finish = -1;
    	int32_t petid = -1;
    	int32_t petlvl = 0;
    };
    trainroom_t _train[MaxTrainRoomNum];
    set<int32_t> _train_mods;
    void _init_train(const Json::Value &json);
    void _save_train(Json::Value &json);
    void _destroy_train();
    void _fill_train_init(cs::OPlayer* oplayer);
    void _fill_train_sync(cs::SPlayerSync* splayersync);

private:
    void destroy();
};

struct level_t : unit_t {
    bool init_level(int32_t protoid);
    bool init_worldboss(int32_t protoid, int32_t level);
    void destroy();

    bool init_player(pet_t* pet);
    void destroy_player();
};

#endif /* PLAYER_DATA_H_ */
